class SignalRService {
  constructor() {
    this.connection = null
    this.gameStore = null
    this.isConnected = false
    this.eventCallbacks = new Map()
    this.reconnectAttempts = 0
    this.maxReconnectAttempts = 5
    this.reconnectDelay = 2000
    this.messageQueue = [] // 消息队列，用于离线时缓存消息
    this.maxQueueSize = 100
    this.lastPingTime = 0
    this.pingInterval = null
    this.connectionHealthCheck = null

    // 计时器
    this.countdownInterval = null
    this.countdownEndAt = 0
    this.countdownRoomCode = null
  }

  // 设置store引用
  setStore(store) {
    this.gameStore = store
  }

  // 延迟初始化store
  initStore() {
    if (!this.gameStore) {
      console.warn('GameStore not initialized yet')
      return false
    }
    return true
  }

  async connect() {
    try {
      // 动态导入SignalR客户端
      const { HubConnectionBuilder, LogLevel } = await import('@microsoft/signalr')
      
      console.log('正在连接到SignalR服务器...')
      
      const { useAuthStore } = await import('@/stores/auth')
      const auth = useAuthStore()
      this.connection = new HubConnectionBuilder()
        .withUrl('http://localhost:5000/gamehub', {
          withCredentials: false,
          accessTokenFactory: () => auth?.token || ''
        })
        .withAutomaticReconnect([0, 2000, 10000, 30000]) // 自动重连策略
        .configureLogging(LogLevel.Debug) // 使用Debug级别获取更多信息
        .build()

      this.setupEventListeners()
      
      console.log('开始建立连接...')
      await this.connection.start()
      
      console.log('已连接到SignalR服务器')
      this.isConnected = true
      this.reconnectAttempts = 0
      
      if (this.initStore()) {
        this.gameStore.setConnectionStatus(true)
      }
      
      // 发送连接确认
      this.triggerEvent('Connected', { timestamp: new Date() })
      
      // 启动健康检查
      this.startHealthCheck()
      
      // 处理离线时缓存的消息
      this.processMessageQueue()
      
    } catch (error) {
      console.error('连接SignalR服务器失败:', error)
      this.handleConnectionError(error)
    }
  }

  setupEventListeners() {
    if (!this.connection) return

    // 连接事件
    this.connection.onreconnecting((error) => {
      console.log('正在重新连接...', error)
      this.isConnected = false
      this.reconnectAttempts++
      this.triggerEvent('Reconnecting', { error, attempt: this.reconnectAttempts })
    })

    this.connection.onreconnected((connectionId) => {
      console.log('重新连接成功:', connectionId)
      this.isConnected = true
      this.reconnectAttempts = 0
      this.triggerEvent('Reconnected', { connectionId })
      
      // 重新连接后处理消息队列
      this.processMessageQueue()
    })

    this.connection.onclose((error) => {
      console.log('连接已关闭:', error)
      this.isConnected = false
      this.triggerEvent('Disconnected', { error })
      
      if (this.initStore()) {
        this.gameStore.setConnectionStatus(false)
      }
      
      // 停止健康检查
      this.stopHealthCheck()
    })

    // 游戏事件
    this.connection.on('Connected', (data) => {
      console.log('连接确认:', data)
      this.triggerEvent('Connected', data)
    })

    this.connection.on('WelcomeMessage', (data) => {
      console.log('欢迎消息:', data)
      this.triggerEvent('WelcomeMessage', data)
    })

    this.connection.on('PlayerJoined', (playerInfo) => {
      console.log('玩家加入:', playerInfo)
      if (this.initStore()) {
        const normalized = {
          id: playerInfo.PlayerId,
          nickname: playerInfo.Nickname,
          avatarColor: playerInfo.AvatarColor,
          brushColor: playerInfo.BrushColor,
          joinedAt: playerInfo.JoinedAt,
          isOwner: false
        }
        this.gameStore.addPlayer(normalized)
        
        // 如果是当前玩家，更新当前玩家的颜色
        if (this.gameStore.currentPlayer && this.gameStore.currentPlayer.id === playerInfo.PlayerId) {
          this.gameStore.setCurrentPlayer({
            ...this.gameStore.currentPlayer,
            avatarColor: playerInfo.AvatarColor,
            brushColor: playerInfo.BrushColor
          })
        }
      }
      this.triggerEvent('PlayerJoined', playerInfo)
    })

    this.connection.on('PlayerLeft', (playerInfo) => {
      console.log('玩家离开:', playerInfo)
      if (this.initStore()) {
        // 游戏结束后忽略离开事件，避免弹窗后面的列表人数减少
        if (this.gameStore.gameStatus !== 'finished') {
          this.gameStore.removePlayer(playerInfo.PlayerId)
        }
      }
      this.triggerEvent('PlayerLeft', playerInfo)
    })

    this.connection.on('PlayerDisconnected', (playerInfo) => {
      console.log('玩家断开连接:', playerInfo)
      if (this.initStore()) {
        // 游戏结束后忽略断开事件，避免弹窗后面的列表人数减少
        if (this.gameStore.gameStatus !== 'finished') {
          this.gameStore.removePlayer(playerInfo.PlayerId)
        }
      }
      this.triggerEvent('PlayerDisconnected', playerInfo)
    })

    this.connection.on('GameStarted', (gameInfo) => {
      console.log('游戏开始:', gameInfo)
      if (this.initStore()) {
        this.gameStore.setGameStatus('playing')
        const duration = Number(
          (gameInfo && gameInfo.GameDuration != null ? gameInfo.GameDuration
            : (gameInfo && gameInfo.gameDuration != null ? gameInfo.gameDuration
              : (this.gameStore && this.gameStore.gameDuration) )) || 180
        )
        const startedAtStr = (gameInfo && gameInfo.StartedAt != null) ? gameInfo.StartedAt : (gameInfo ? gameInfo.startedAt : undefined)
        const roomId = (this.gameStore && this.gameStore.currentRoom && this.gameStore.currentRoom.id) || null
        this.startCountdown(roomId, duration, startedAtStr)
      }
      this.triggerEvent('GameStarted', gameInfo)
    })

    this.connection.on('GameEnded', (gameInfo) => {
      console.log('游戏结束:', gameInfo)
      if (this.initStore()) {
        this.gameStore.setGameStatus('finished')
        this.stopCountdown()
        this.gameStore.setTimeLeft(0)
      }
      this.triggerEvent('GameEnded', gameInfo)
    })

    this.connection.on('PaintActionReceived', (paintData) => {
      console.log('SignalR收到涂色动作:', paintData)
      console.log('paintData类型:', typeof paintData)
      console.log('paintData键:', Object.keys(paintData || {}))
      console.log('paintData完整内容:', JSON.stringify(paintData, null, 2))
      this.triggerEvent('PaintActionReceived', paintData)
    })

    this.connection.on('AreaUpdated', (areaStats) => {
      console.log('面积更新:', areaStats)
      const playerId = areaStats ? (areaStats.PlayerId != null ? areaStats.PlayerId : (areaStats.playerId != null ? areaStats.playerId : areaStats.id)) : undefined
      const area = areaStats ? (areaStats.Area != null ? areaStats.Area : (areaStats.area != null ? areaStats.area : 0)) : 0
      if (this.initStore() && playerId != null) {
        this.gameStore.updatePlayerArea(playerId, area)
      }
      this.triggerEvent('AreaUpdated', areaStats)
    })

    this.connection.on('ChatMessage', (messageData) => {
      console.log('聊天消息:', messageData)
      if (this.initStore()) {
        this.gameStore.addChatMessage(messageData)
      }
      this.triggerEvent('ChatMessage', messageData)
    })

    this.connection.on('GameSettingsUpdated', (settingsData) => {
      console.log('游戏设置已更新:', settingsData)
      if (this.initStore()) {
        const duration = (settingsData && settingsData.GameDuration != null)
          ? settingsData.GameDuration
          : (settingsData && settingsData.gameDuration != null ? settingsData.gameDuration : this.gameStore.gameDuration)
        const brush = (settingsData && settingsData.BrushSize != null)
          ? settingsData.BrushSize
          : (settingsData && settingsData.brushSize != null ? settingsData.brushSize : this.gameStore.brushSize)
        this.gameStore.setGameDuration(Number(duration))
        this.gameStore.setBrushSize(Number(brush))
      }
      this.triggerEvent('GameSettingsUpdated', settingsData)
    })

    this.connection.on('RoomStateUpdated', (roomState) => {
      console.log('房间状态更新:', roomState)
      if (this.initStore()) {
        // 游戏结束后，冻结玩家列表，避免退出导致人数减少
        if (this.gameStore.gameStatus === 'finished') {
          this.triggerEvent('RoomStateUpdated', roomState)
          return
        }
        // 如果后端未提供 PlayerCount，则由前端依据 Players 推导
        if (typeof roomState.PlayerCount !== 'number' && Array.isArray(roomState.Players)) {
          roomState.PlayerCount = roomState.Players.length
        }
        this.gameStore.setRoomInfo(roomState)

        // 如果处于进行中，根据服务器时间校准并启动倒计时
        const status = (roomState && roomState.GameStatus != null) ? roomState.GameStatus : (roomState ? roomState.gameStatus : undefined)
        if (status === 'Playing' || status === 'playing') {
          const duration = Number(
            (roomState && roomState.GameDuration != null ? roomState.GameDuration
              : (roomState && roomState.gameDuration != null ? roomState.gameDuration
                : (this.gameStore && this.gameStore.gameDuration) )) || 180
          )
          const startedAtStr = (roomState && roomState.GameStartedAt != null) ? roomState.GameStartedAt : (roomState ? roomState.gameStartedAt : undefined)
          const roomId = (this.gameStore && this.gameStore.currentRoom && this.gameStore.currentRoom.id) || null
          this.startCountdown(roomId, duration, startedAtStr)
        }
      }
      this.triggerEvent('RoomStateUpdated', roomState)
    })

    this.connection.on('RoomInfo', (roomInfo) => {
      console.log('房间信息:', roomInfo)
      if (this.initStore()) {
        // 游戏结束后，冻结玩家列表，避免退出导致人数减少
        if (this.gameStore.gameStatus === 'finished') {
          this.triggerEvent('RoomInfo', roomInfo)
          return
        }
        this.gameStore.setRoomInfo(roomInfo)

        // 根据房间信息启动/校准倒计时
        const status = (roomInfo && roomInfo.GameStatus != null) ? roomInfo.GameStatus : (roomInfo ? roomInfo.gameStatus : undefined)
        if (status === 'Playing' || status === 'playing') {
          const duration = Number(
            (roomInfo && roomInfo.GameDuration != null ? roomInfo.GameDuration
              : (roomInfo && roomInfo.gameDuration != null ? roomInfo.gameDuration
                : (this.gameStore && this.gameStore.gameDuration) )) || 180
          )
          const startedAtStr = (roomInfo && roomInfo.GameStartedAt != null) ? roomInfo.GameStartedAt : (roomInfo ? roomInfo.gameStartedAt : undefined)
          const roomId = (this.gameStore && this.gameStore.currentRoom && this.gameStore.currentRoom.id) || null
          this.startCountdown(roomId, duration, startedAtStr)
        }
      }
      this.triggerEvent('RoomInfo', roomInfo)
    })

    // 房间创建成功（仅发送给房主）
    this.connection.on('RoomCreated', (data) => {
      console.log('房间创建成功:', data)
      if (this.initStore()) {
        this.gameStore.setRoom({
          id: data.RoomCode,
          name: data.RoomName,
          maxPlayers: data.MaxPlayers
        })

        // 确保房主也出现在玩家列表中（立即显示）
        if (this.gameStore.currentPlayer) {
          // 使用后端分配的颜色
          const ownerAvatarColor = data.AvatarColor || this.gameStore.currentPlayer.avatarColor
          const ownerBrushColor = data.BrushColor || this.gameStore.currentPlayer.brushColor
          
          // 更新当前玩家的颜色
          this.gameStore.setCurrentPlayer({
            ...this.gameStore.currentPlayer,
            avatarColor: ownerAvatarColor,
            brushColor: ownerBrushColor
          })
          
          const ownerAsPlayer = {
            id: this.gameStore.currentPlayer.id,
            nickname: this.gameStore.currentPlayer.nickname,
            avatarColor: ownerAvatarColor,
            brushColor: ownerBrushColor,
            joinedAt: Date.now(),
            isOwner: true
          }
          this.gameStore.addPlayer(ownerAsPlayer)
          
          console.log('房主头像颜色已设置:', ownerAvatarColor)
          console.log('房主画笔颜色已设置:', ownerBrushColor)
        }
      }
      this.triggerEvent('RoomCreated', data)
    })

    this.connection.on('RoomNotFound', (data) => {
      console.log('房间未找到:', data)
      this.triggerEvent('RoomNotFound', data)
    })

    this.connection.on('Pong', (data) => {
      console.log('Pong响应:', data)
      this.lastPingTime = Date.now()
      this.triggerEvent('Pong', data)
    })
  }

  // 消息队列管理
  addToMessageQueue(message) {
    if (this.messageQueue.length >= this.maxQueueSize) {
      this.messageQueue.shift() // 移除最旧的消息
    }
    this.messageQueue.push({
      ...message,
      timestamp: Date.now()
    })
    console.log('消息已添加到队列，当前队列长度:', this.messageQueue.length)
  }

  async processMessageQueue() {
    if (!this.isConnected || this.messageQueue.length === 0) {
      return
    }

    console.log('处理消息队列，队列长度:', this.messageQueue.length)
    
    const messagesToProcess = [...this.messageQueue]
    this.messageQueue = [] // 清空队列

    for (const message of messagesToProcess) {
      try {
        await this.sendQueuedMessage(message)
        console.log('队列消息发送成功:', message.type)
      } catch (error) {
        console.error('队列消息发送失败，重新加入队列:', error)
        this.addToMessageQueue(message) // 重新加入队列
      }
      
      // 添加小延迟避免消息发送过快
      await new Promise(resolve => setTimeout(resolve, 50))
    }
  }

  async sendQueuedMessage(message) {
    switch (message.type) {
      case 'paint':
        await this.connection.invoke('Paint', message.roomCode, message.playerId, 
          message.x, message.y, message.color, message.brushSize, message.tool)
        break
      case 'paintWithData':
        await this.connection.invoke('PaintWithData', message.roomCode, message.playerId, message.paintData)
        break
      case 'chat':
        await this.connection.invoke('SendChatMessage', message.roomCode, message.playerId, message.message)
        break
      case 'area':
        await this.connection.invoke('UpdateArea', message.roomCode, message.playerId, message.area)
        break
      default:
        console.warn('未知的消息类型:', message.type)
    }
  }

  // 健康检查
  startHealthCheck() {
    // 定期发送ping
    this.pingInterval = setInterval(async () => {
      if (this.isConnected) {
        try {
          await this.ping()
        } catch (error) {
          console.warn('Ping失败:', error)
        }
      }
    }, 30000) // 每30秒ping一次

    // 连接健康检查
    this.connectionHealthCheck = setInterval(() => {
      if (this.isConnected && this.lastPingTime > 0) {
        const timeSinceLastPing = Date.now() - this.lastPingTime
        if (timeSinceLastPing > 60000) { // 超过1分钟没有ping响应
          console.warn('连接可能不稳定，尝试重新连接')
          this.reconnect()
        }
      }
    }, 10000) // 每10秒检查一次
  }

  stopHealthCheck() {
    if (this.pingInterval) {
      clearInterval(this.pingInterval)
      this.pingInterval = null
    }
    if (this.connectionHealthCheck) {
      clearInterval(this.connectionHealthCheck)
      this.connectionHealthCheck = null
    }
  }

  async reconnect() {
    console.log('手动重连...')
    this.isConnected = false
    await this.disconnect()
    await this.connect()
  }

  async updateGameSettings(roomCode, playerId, gameDuration, brushSize) {
    if (!this.connection || !this.isConnected) {
      throw new Error('未连接到服务器')
    }

    try {
      // 确保参数是数字类型
      const duration = parseInt(gameDuration, 10)
      const brush = parseInt(brushSize, 10)
      
      await this.connection.invoke('UpdateGameSettings', roomCode, playerId, duration, brush)
      console.log('游戏设置已更新:', { roomCode, gameDuration: duration, brushSize: brush })
    } catch (error) {
      console.error('更新游戏设置失败:', error)
      throw error
    }
  }

  async createRoom(roomCode, roomName, maxPlayers, password, playerId, nickname, playerColor = '') {
    if (!this.connection || !this.isConnected) {
      throw new Error('未连接到服务器')
    }
    try {
      // 先设置当前玩家到 GameStore
      if (this.initStore()) {
        this.gameStore.setCurrentPlayer({
          id: playerId,
          nickname: nickname,
          avatarColor: '',
          brushColor: '',
          isOwner: true
        })
      }
      
      await this.connection.invoke('CreateRoom', roomCode, roomName, maxPlayers, password, playerId, nickname, playerColor)
      console.log('房间创建成功:', roomCode, roomName)
    } catch (error) {
      console.error('创建房间失败:', error)
      throw error
    }
  }

  async joinRoom(roomCode, playerId, nickname, password = '', playerColor = '') {
    if (!this.connection || !this.isConnected) {
      throw new Error('未连接到服务器')
    }

    try {
      // 先设置当前玩家到 GameStore
      if (this.initStore()) {
        this.gameStore.setCurrentPlayer({
          id: playerId,
          nickname: nickname,
          avatarColor: '',
          brushColor: '',
          isOwner: false
        })
      }
      
      await this.connection.invoke('JoinRoom', roomCode, playerId, nickname, playerColor, password)
      console.log('已加入房间:', roomCode)

      // 加入成功后，主动拉取一次房间信息，确保包含房主等全部玩家
      try {
        await this.getRoomInfo(roomCode)
      } catch (e) {
        console.warn('加入后主动获取房间信息失败（忽略）：', e)
      }
    } catch (error) {
      console.error('加入房间失败:', error)
      throw error
    }
  }

  async leaveRoom(roomCode, playerId) {
    if (!this.connection || !this.isConnected) {
      console.log('连接已断开，无需离开房间')
      return
    }

    try {
      await this.connection.invoke('LeaveRoom', roomCode, playerId)
      console.log('已离开房间:', roomCode)
    } catch (error) {
      if (error.message.includes('connection being closed')) {
        console.log('连接已关闭，房间离开操作被跳过')
      } else {
        console.error('离开房间失败:', error)
        throw error
      }
    }
  }

  async startGame(roomCode, gameSettings = {}) {
    if (!this.connection || !this.isConnected) {
      throw new Error('未连接到服务器')
    }

    try {
      // 确保参数是数字类型
      const duration = parseInt(gameSettings.gameDuration || 180, 10)
      const brush = parseInt(gameSettings.brushSize || 12, 10)
      
      // 传递游戏设置参数
      await this.connection.invoke('StartGame', roomCode, duration, brush)
      console.log('游戏已开始:', roomCode, '设置:', { gameDuration: duration, brushSize: brush })
      // 本地预启动倒计时，等待服务端校准
      if (this.initStore()) {
        this.startCountdown(roomCode, duration, new Date().toISOString())
      }
    } catch (error) {
      console.error('开始游戏失败:', error)
      throw error
    }
  }

  async endGame(roomCode) {
    if (!this.connection || !this.isConnected) {
      return
    }

    try {
      await this.connection.invoke('EndGame', roomCode)
      console.log('游戏已结束:', roomCode)
    } catch (error) {
      console.error('结束游戏失败:', error)
    }
  }

  async sendPaintAction(roomCode, playerId, x, y, color, brushSize, tool) {
    if (!this.connection || !this.isConnected) {
      // 如果未连接，将消息添加到队列
      this.addToMessageQueue({
        type: 'paint',
        roomCode,
        playerId,
        x,
        y,
        color,
        brushSize,
        tool
      })
      return
    }

    try {
      await this.connection.invoke('Paint', roomCode, playerId, x, y, color, brushSize, tool)
      console.log('涂色动作发送成功:', { x, y, tool, color, brushSize })
    } catch (error) {
      console.error('发送涂色动作失败:', error)
      // 发送失败时也加入队列
      this.addToMessageQueue({
        type: 'paint',
        roomCode,
        playerId,
        x,
        y,
        color,
        brushSize,
        tool
      })
      throw error
    }
  }

  async sendPaintActionWithData(roomCode, playerId, paintData) {
    if (!this.connection || !this.isConnected) {
      // 如果未连接，将消息添加到队列
      this.addToMessageQueue({
        type: 'paintWithData',
        roomCode,
        playerId,
        paintData
      })
      return
    }

    try {
      // 发送包含起始点的数据
      await this.connection.invoke('PaintWithData', roomCode, playerId, paintData)
      console.log('涂色动作发送成功:', paintData)
    } catch (error) {
      console.error('发送涂色动作失败:', error)
      // 发送失败时也加入队列
      this.addToMessageQueue({
        type: 'paintWithData',
        roomCode,
        playerId,
        paintData
      })
      throw error
    }
  }

  async updateArea(roomCode, playerId, area) {
    if (!this.connection || !this.isConnected) {
      this.addToMessageQueue({
        type: 'area',
        roomCode,
        playerId,
        area
      })
      return
    }

    try {
      await this.connection.invoke('UpdateArea', roomCode, playerId, area)
    } catch (error) {
      console.error('更新面积失败:', error)
      this.addToMessageQueue({
        type: 'area',
        roomCode,
        playerId,
        area
      })
    }
  }

  async sendChatMessage(roomCode, playerId, message) {
    if (!this.connection || !this.isConnected) {
      this.addToMessageQueue({
        type: 'chat',
        roomCode,
        playerId,
        message
      })
      return
    }

    try {
      await this.connection.invoke('SendChatMessage', roomCode, playerId, message)
    } catch (error) {
      console.error('发送聊天消息失败:', error)
      this.addToMessageQueue({
        type: 'chat',
        roomCode,
        playerId,
        message
      })
    }
  }

  async getRoomInfo(roomCode) {
    if (!this.connection || !this.isConnected) {
      throw new Error('未连接到服务器')
    }

    try {
      await this.connection.invoke('GetRoomInfo', roomCode)
    } catch (error) {
      console.error('获取房间信息失败:', error)
      throw error
    }
  }

  async ping() {
    if (!this.connection || !this.isConnected) {
      return
    }

    try {
      await this.connection.invoke('Ping')
    } catch (error) {
      console.error('Ping失败:', error)
    }
  }

  async disconnect() {
    if (!this.connection) {
      console.log('连接不存在，无需断开')
      return
    }

    try {
      // 检查连接状态
      if (this.connection.state === 'Connected') {
        await this.connection.stop()
        console.log('连接已正常断开')
      } else {
        console.log('连接状态为:', this.connection.state, '，跳过断开操作')
      }
    } catch (error) {
      if (error.message.includes('connection being closed')) {
        console.log('连接已关闭，无需再次断开')
      } else {
        console.error('断开连接失败:', error)
      }
    } finally {
      this.connection = null
      this.isConnected = false
      this.stopHealthCheck()
      if (this.initStore()) {
        this.gameStore.setConnectionStatus(false)
      }
    }
  }

  handleConnectionError(error) {
    console.error('连接错误:', error)
    this.isConnected = false
    
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      setTimeout(() => {
        console.log(`尝试重新连接... (${this.reconnectAttempts + 1}/${this.maxReconnectAttempts})`)
        this.connect()
      }, this.reconnectDelay)
    } else {
      console.error('达到最大重连次数，停止重连')
      this.triggerEvent('MaxReconnectAttemptsReached', { error })
    }
  }

  // 添加自定义事件监听器
  on(event, callback) {
    if (!this.eventCallbacks.has(event)) {
      this.eventCallbacks.set(event, [])
    }
    this.eventCallbacks.get(event).push(callback)
  }

  // 移除事件监听器
  off(event, callback) {
    if (this.eventCallbacks.has(event)) {
      const callbacks = this.eventCallbacks.get(event)
      const index = callbacks.indexOf(callback)
      if (index > -1) {
        callbacks.splice(index, 1)
      }
    }
  }

  // 触发自定义事件
  triggerEvent(event, data) {
    if (this.eventCallbacks.has(event)) {
      this.eventCallbacks.get(event).forEach(callback => {
        try {
          callback(data)
        } catch (error) {
          console.error(`Error in event callback for ${event}:`, error)
        }
      })
    }
  }

  // 获取连接状态
  getConnectionStatus() {
    return this.isConnected
  }

  // 获取连接ID
  getConnectionId() {
    return this.connection?.connectionId
  }

  // 获取消息队列状态
  getMessageQueueStatus() {
    return {
      queueLength: this.messageQueue.length,
      maxQueueSize: this.maxQueueSize,
      isConnected: this.isConnected
    }
  }

  // 清空消息队列
  clearMessageQueue() {
    this.messageQueue = []
    console.log('消息队列已清空')
  }

  // ===== 倒计时 =====
  startCountdown(roomCode, durationSec, startedAtIsoString) {
    try {
      let startedAt
      if (startedAtIsoString) {
        // 兼容后端可能传递的UTC字符串
        const parsed = Date.parse(String(startedAtIsoString))
        startedAt = isNaN(parsed) ? Date.now() : parsed
      } else {
        startedAt = Date.now()
      }
      const endAt = startedAt + Number(durationSec) * 1000
      this.countdownEndAt = endAt
      this.countdownRoomCode = roomCode
      this.tickCountdown() // 立即计算一次
      if (this.countdownInterval) clearInterval(this.countdownInterval)
      this.countdownInterval = setInterval(() => this.tickCountdown(), 1000)
    } catch (e) {
      console.warn('启动倒计时失败，使用本地时间回退:', e)
      const endAt = Date.now() + Number(durationSec) * 1000
      this.countdownEndAt = endAt
      this.countdownRoomCode = roomCode
      if (this.countdownInterval) clearInterval(this.countdownInterval)
      this.countdownInterval = setInterval(() => this.tickCountdown(), 1000)
    }
  }

  tickCountdown() {
    if (!this.initStore()) return
    if (!this.countdownEndAt) return
    const now = Date.now()
    let left = Math.max(0, Math.floor((this.countdownEndAt - now) / 1000))
    this.gameStore.setTimeLeft(left)
    if (left <= 0) {
      this.stopCountdown()
      // 主动切换状态，避免网络延迟
      this.gameStore.setGameStatus('finished')
      try { this.endGame(this.countdownRoomCode) } catch (_) {}
    }
  }

  stopCountdown() {
    if (this.countdownInterval) {
      clearInterval(this.countdownInterval)
      this.countdownInterval = null
    }
    this.countdownEndAt = 0
  }
}

// 创建单例实例
let signalRService = null

// 导出工厂函数，允许组件在需要时初始化store
export const createSignalRService = (store) => {
  if (!signalRService) {
    console.log('创建新的SignalR服务实例')
    signalRService = new SignalRService()
  } else {
    console.log('使用现有的SignalR服务实例')
  }
  
  signalRService.setStore(store)
  return signalRService
}

export default signalRService
